package com.china.cnlongdb;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.china.cnlongdb.basic.constant.LongDbConstant;
import com.china.cnlongdb.basic.entity.database.LongDataBaseEntity;
import com.china.cnlongdb.basic.entity.database.LongTableEntity;
import com.china.cnlongdb.basic.entity.query.LongDbQuery;
import com.china.cnlongdb.basic.entity.update.LongDbUpdate;
import com.china.cnlongdb.plugin.LongdbPluginManager;
import com.china.cnlongdb.server.config.LongdbConfigHandler;
import com.china.cnlongdb.server.connect.LongDbConnect;
import com.china.cnlongdb.server.engine.LongDbEngine;
import com.china.cnlongdb.server.service.LongDbService;
import com.china.cnlongdb.server.transaction.LongdbTransactionManager;

/**
 * 系统名称：LongDbServer.java
 * 模块名称：
 * 模块描述：longdb - 数据库提供的接口服务实现层
 * 功能列表：
 * 模块作者：ZOUYONG
 * 开发时间：2018年12月5日 下午10:11:17
 * 模块路径：com.china.cnlongdb.server.LongDbServer
 * 更新记录：
 */
public class LongDbServer implements LongDbService {
	
	private final Logger logger = (Logger) LoggerFactory.getLogger(LongDbServer.class);

	// 数据库连接对象
	private LongDbConnect connect;
	
	// 插件工具管理对象
	private LongdbPluginManager pluginManager;
	
	/**
	 * 构建[中国龙cnlongdb]数据库操作对象
	 * @param connect
	 */
	public LongDbServer(String longdbConfigPath) {
		// 读取指定文件中的数据库配置新
		unifiedHandlerLongDbServer(longdbConfigPath);
	}
	
	/**
	 * 构建[中国龙cnlongdb]数据库操作对象
	 * @param connect
	 */
	public LongDbServer(String dataBaseRootDirectory, 
			String dataBaseName, String dataBaseIp, int dataBasePort, String longdbConfigPath) {
		this.connect = new LongDbConnect(dataBaseRootDirectory, dataBaseName, dataBaseIp, dataBasePort);
		// 读取指定文件中的数据库配置新
		unifiedHandlerLongDbServer(longdbConfigPath);
	}

	/**
	 * 功能描述：统一处理初始化的后续事件
	 * 模块作者：ZOUYONG
	 * 开发时间：2019年4月13日 上午11:03:39
	 * 更新记录：
	 * 返回数据：void
	 */
	private void unifiedHandlerLongDbServer(String longdbConfigPath) {
		logger.info("实例化" + LongDbConstant.longdbDefaultName + "数据库连接对象：{}", JSON.toJSONString(connect));
		// 加载各种配置信息
		loadLongdbConfig(longdbConfigPath);
		// 初始化各种协助器
		initAssistActuator();
	}

	/**
	 * 功能描述：加载各种配置信息
	 × 模块作者：ZOUYONG
	 × 开发时间：2018年12月22日 下午5:16:46
	 × 返回数据：void
	 */
	private void loadLongdbConfig(String longdbConfigPath) {
		if(StringUtils.isBlank(longdbConfigPath)) {
			return;
		}
		URL url = this.getClass().getClassLoader().getResource(longdbConfigPath);
		if(null == url) {
			logger.debug("未加载到" + LongDbConstant.longdbDefaultName + "的配置信息！");
			return;
		}
		List<File> ruleList = new ArrayList<File>();
		File file = new File(url.getPath());
		if(!file.exists()) {
			logger.info(LongDbConstant.longdbDefaultName + "配置目录中没有文件！");
			return;
		}
		File[] files = file.listFiles();
		if(null == files || files.length == 0) {
			logger.info(LongDbConstant.longdbDefaultName + "配置目录为空！");
			return;
		}
		
		for (File fi : files) {
			// 获取数据库总配置
			if(fi.isFile() && fi.getName().endsWith(LongDbConstant.longdbCfgSuffix) && null == connect) {
				// 对数据库连接对象进行初始化
				this.connect = LongdbConfigHandler.getLongdbConnect(fi);
			}
			// 获取表分区配置关系
			else if(fi.isFile() && fi.getName().endsWith(LongDbConstant.longdbRuleSuffix)) {
				ruleList.add(fi);
			}
		}
		
		if(ruleList.size() > 0) {
			LongdbConfigHandler.initLongdbRuleData(ruleList, connect);
		}
	}

	/**
	 * 功能描述：初始化各种协助器
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年12月8日 上午11:50:33
	 * 更新记录：
	 * 返回数据：void
	 */
	private void initAssistActuator() {
		// 初始化事务管理器
		LongdbTransactionManager.setConnect(connect);
		// 初始化执行引擎
		LongDbEngine.startEngineMonitor(connect);
		// 实例化插件工具管理类
		pluginManager = new LongdbPluginManager(connect);
	}

	/**
	 * 功能描述：创建数据库操作
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月9日 下午2:56:05
	 * 更新记录：
	 */
	@Override
	public LongDataBaseEntity createDataBase(String dataBaseName) throws Exception {
		
		return connect.getCreateOperator().createDataBase(dataBaseName);
	}

	/**
	 * 功能描述：创建数据库表的操作
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月9日 下午2:56:18
	 * 更新记录：
	 */
	@Override
	public LongTableEntity createTable(String tableName) throws Exception {
		
		return connect.getCreateOperator().createTable(tableName);
	}

	/**
	 * 功能描述：获取指定数据库的配置信息
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月9日 下午6:29:57
	 * 更新记录：
	 */
	@Override
	public LongDataBaseEntity getLongDataBaseEntity(String dataBaseName) throws Exception {
		
		return connect.getCreateOperator().getLongDataBaseEntity(dataBaseName);
	}

	/**
	 * 功能描述：向表中插入数据
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月9日 下午3:40:53
	 * 更新记录：
	 */
	@Override
	public boolean insert(Object object) throws Exception {
		
		return connect.getInsertOperator().insert(object, object.getClass().getSimpleName(), false);
	}

	/**
	 * 功能描述：指定表名，插入数据
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月9日 下午3:41:01
	 * 更新记录：
	 */
	@Override
	public boolean insert(Object object, String tableName) throws Exception {
		
		return connect.getInsertOperator().insert(object, tableName, false);
	}

	/**
	 * 功能描述：指定表名，异步插入数据
	 * 模块作者：ZOUYONG
	 * 开发时间：2019年04月15日 下午3:41:01
	 * 更新记录：
	 */
	@Override
	public boolean insert(Object object, String tableName, boolean isynchronized) throws Exception {

		return connect.getInsertOperator().insert(object, tableName, isynchronized);
	}
	
	/**
	 * 功能描述：向表中批量插入数据
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月9日 下午3:41:09
	 * 更新记录：
	 */
	@Override
	public boolean insertAll(List<Object> objectList, boolean isynchronized) throws Exception {
		if(null == objectList || CollectionUtils.isEmpty(objectList)) {
			return false;
		}
		for (Object object : objectList) {
			connect.getInsertOperator().insert(object, object.getClass().getSimpleName(), true);
		}
		return true;
	}
	
	/**
	 * 功能描述：指定表名，向表中批量插入数据
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月9日 下午3:41:15
	 * 更新记录：
	 */
	@Override
	public boolean insertAll(List<Object> objectList, String tableName, boolean isynchronized) throws Exception {
		if(null == objectList || CollectionUtils.isEmpty(objectList)) {
			return false;
		}
		for (Object object : objectList) {
			connect.getInsertOperator().insert(object, tableName, true);
		}
		return true;
	}
	
	/**
	 * 功能描述：查询表中所有数据
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月10日 下午1:05:03
	 * 更新记录：
	 */
	@Override
	public <T> List<T> findAll(Class<T> cls) throws Exception {
		
		return connect.getQueryOperator().findAll(cls, null, null);
	}
	
	/**
	 * 功能描述：指定表名查询全部
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月11日 上午6:50:51
	 * 更新记录：
	 */
	@Override
	public <T> List<T> findAll(Class<T> cls, String tableName) throws Exception {
		
		return connect.getQueryOperator().findAll(cls, tableName, null);
	}
	
	/**
	 * 功能描述：根据条件查询数据集合
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月10日 下午1:40:44
	 * 更新记录：
	 * 返回数据：List<T>
	 */
	@Override
	public <T> List<T> find(LongDbQuery query) throws Exception {
		return connect.getQueryOperator().find(query);
	}
	
	/**
	 * 功能描述：根据主键ID查询
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月11日 上午7:09:03
	 * 更新记录：
	 */
	@Override
	public <T> T findById(String longId, Class<T> cls) throws Exception {
		if(null == cls || StringUtils.isBlank(longId)) {
			return null;
		}
		return findById(longId, cls, cls.getSimpleName());
	}
	
	/**
	 * 功能描述：根据主键ID查询-指定表名
	 * 模块作者：ZOUYONG
	 * 开发时间：2018年11月11日 上午7:09:37
	 * 更新记录：
	 */
	@Override
	public <T> T findById(String id, Class<T> cls, String tableName) throws Exception {

		return connect.getQueryOperator().findById(id, cls, tableName);
	}
	
	// 根据条件查询一条数据
	@Override
	public <T> T findOne(LongDbQuery query) throws Exception {
		return connect.getQueryOperator().findOne(query);
	}
	
	// 查询总数
	@Override
	public long count(String tableName) throws Exception {
		
		return connect.getQueryOperator().count(tableName, null);
	}

	// 查询总数
	@Override
	public <T> long count(Class<T> cls) throws Exception {
		if(null == cls) {
			return 0;
		}
		return connect.getQueryOperator().count(cls.getSimpleName(), null);
	}
	
	// 根据条件查询总数
	@Override
	public long count(LongDbQuery query) throws Exception {
		return connect.getQueryOperator().count(query);
	}
	
	// 删除指定表中数据
	@Override
	public boolean remove(String tableName) throws Exception {
		
		return connect.getRemoveOperator().remove(tableName);
	}
	
	// 删除类相关表中数据
	@Override
	public boolean remove(Class<?> cls) throws Exception {
		if(null == cls) {
			return false;
		}
		return connect.getRemoveOperator().remove(cls.getSimpleName());
	}
	
	// 删除查询出来后的数据
	@Override
	public boolean remove(LongDbQuery query) throws Exception {
		return connect.getRemoveOperator().remove(query);
	}
	
	// 删除表及数据
	@Override
	public boolean drop(String tableName) throws Exception {

		return connect.getRemoveOperator().drop(tableName);
	}
	
	// 更新表中数据记录
	@Override
	public boolean update(LongDbQuery query, LongDbUpdate update) throws Exception {
		return connect.getUpdateOperator().update(query, update);
	}
	
	// 根据条件，全部更新，慎用
	@Override
	public boolean update(LongDbQuery query, Object object) throws Exception {
		return connect.getUpdateOperator().update(query, object);
	}
	
	// 删除表及数据
	@Override
	public boolean drop(Class<?> cls) throws Exception {
		if(null == cls) {
			return false;
		}
		return connect.getRemoveOperator().drop(cls.getSimpleName());
	}
	
	// 删除数据库
	@Override
	public boolean dropDataBase(String dataBaseName) throws Exception {
		
		return connect.getRemoveOperator().dropDataBase(dataBaseName);
	}
	
	// 根据ID删除数据
	@Override
	public void removeById(String longId, Class<?> cls) throws Exception {
		connect.getRemoveOperator().removeById(longId, cls);
	}
	
	// ================================================ 按年月日区间/表分区字段等查询 ================================================

	// 根据年月日区间查询，格式: 2018-01-01;2018-01-10 (用[;]分号隔开，查询1号到10号的数据)
	@Override
	public <T> List<T> findByYearMothDay(Class<T> cls, String yearMothDayArys) throws Exception {
		if(null == cls) {
			return new ArrayList<T>();
		}
		return connect.getQueryOperator().findAll(cls, cls.getSimpleName(), yearMothDayArys);
	}
	
	// 根据年月日区间查询，格式: 2018-01-01;2018-01-10 (用[;]分号隔开，查询1号到10号的数据)
	@Override
	public <T> List<T> findByYearMothDay(Class<T> cls, String tableName, String yearMothDayArys) throws Exception {
		
		return connect.getQueryOperator().findAll(cls, tableName, yearMothDayArys);
	}
	
	// 根据年月日区间查询，格式: 2018-01-01;2018-01-10 (用[;]分号隔开，查询1号到10号的数据)
	@Override
	public <T> List<T> findByYearMothDay(Class<T> cls, LongDbQuery query, String yearMothDayArys) throws Exception {
		if(null == query) {
			return new ArrayList<T>();
		}
		query.setClassz(cls);
		query.setYearMothDayArys(yearMothDayArys);
		return connect.getQueryOperator().find(query);
	}
	
	// 根据年月日区间查询，格式: 2018-01-01;2018-01-10 (用[;]分号隔开，查询1号到10号的数据)
	@Override
	public <T> List<T> findByYearMothDay(Class<T> cls, LongDbQuery query, String tableName, String yearMothDayArys) throws Exception {
		if(null == query) {
			return new ArrayList<T>();
		}
		query.setClassz(cls);
		query.setYearMothDayArys(yearMothDayArys);
		return connect.getQueryOperator().find(query);
	}
	
	// 根据年月日区间查询，格式: 2018-01-01;2018-01-10 (用[;]分号隔开，查询1号到10号的数据)
	@Override
	public long countByYearMothDay(String tableName, String yearMothDay) throws Exception {
		
		return connect.getQueryOperator().count(tableName, yearMothDay);
	}

	// 根据年月日区间查询，格式: 2018-01-01;2018-01-10 (用[;]分号隔开，查询1号到10号的数据)
	@Override
	public <T> long countByYearMothDay(Class<T> cls, String yearMothDay) throws Exception {
		if(null == cls) {
			return 0;
		}
		return connect.getQueryOperator().count(cls.getSimpleName(), yearMothDay);
	}
	
	// 根据年月日区间查询，格式: 2018-01-01;2018-01-10 (用[;]分号隔开，查询1号到10号的数据)
	@Override
	public long countByYearMothDay(LongDbQuery query, String yearMothDayArys) throws Exception {
		if(null == query) {
			return 0;
		}
		query.setYearMothDayArys(yearMothDayArys);
		return connect.getQueryOperator().count(query);
	}

	public LongDbConnect getConnect() {
		return connect;
	}

	public LongdbPluginManager getPluginManager() {
		return pluginManager;
	}

}
